﻿using HardcoreGame.Common.Helpers;
using HardcoreGame.Common.Players;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using Terraria;
using Terraria.ModLoader;

namespace HardcoreGame.Content.Projectiles.Sets.Heavy.Others
{
    public abstract class HeavyMeleeProjectile : ModProjectile
    {
        public bool AlternateSwings { get; internal set; } = true;
        public float AttackRange { get; internal set; } = 3.1415927f;
        public float HitWindow { get; internal set; } = 0.3f;
        public float HitDistance { get; internal set; } = 18f;

        public float swingProgress;
        public float interpSwingProgress;
        public float peakAmount;
        public float interpPeakAmount;
        public float drawAngle;
        public float drawAngleWithoutFlip;
        public float drawScale;
        public int combo;
        public Vector2 faceVector;
        public Vector2 staticPos;
        public Rectangle hitbox;
        public Vector2 bladeHandle;
        public Vector2 bladeTip;
        protected SpriteEffects spriteFx;
        protected bool isAlternateSwing;
        protected bool useSmartAngle = true;
        protected float drawAngleRangeMod = 1f;
        protected float bladeTipOffsetMod = 1f;
        protected int initialDirection;
        private int itemAnimationMax;
        public void DebugDraw(SpriteBatch sb)
        {
            sb.BeginBlendState(BlendState.NonPremultiplied, null, null, false, false, DrawMode.World, false);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, bladeHandle - Main.screenPosition, null, Color.Green.MultiplyAlpha(0.15f), drawAngleWithoutFlip + 0.7853982f, new Vector2(1f, 2f), (HitDimensions + new Vector2(0f, HitDistance)) / 2f, SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, bladeHandle - Main.screenPosition, null, Color.Red, 0f, new Vector2(1f), 4f, SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, bladeHandle - Main.screenPosition, null, Color.Red.MultiplyAlpha(0.75f), drawAngleWithoutFlip + 0.7853982f, new Vector2(1f), new Vector2(16f, 2f), SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, bladeTip - Main.screenPosition, null, Color.Blue, 0f, new Vector2(1f), 4f, SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, bladeTip - Main.screenPosition, null, Color.Blue.MultiplyAlpha(0.75f), drawAngleWithoutFlip + 0.7853982f, new Vector2(1f), new Vector2(16f, 2f), SpriteEffects.None, 0f);
            Vector2 center = staticPos + new Vector2(0f, 64f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, center - Main.screenPosition, null, Color.Red, 0f, new Vector2(1f), new Vector2(64f, 1f), SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, center - Main.screenPosition, null, (bool)CanDamage() ? Color.White : Color.DarkGray * 0.5f, 0f, new Vector2(1f), new Vector2(64f * (1f - HitWindow), 1f), SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, center + new Vector2(-64f + 128f * swingProgress, 0f) - Main.screenPosition, null, Color.Green, 0f, new Vector2(1f), new Vector2(2f, 4f), SpriteEffects.None, 0f);
            sb.Draw(ModContent.Request<Texture2D>(Texture).Value, center + new Vector2(-64f + 128f * interpSwingProgress, 0f) - Main.screenPosition, null, (bool)CanDamage() ? Color.Yellow : Color.DarkGray * 0.5f, 0f, new Vector2(1f), new Vector2(2f + 4f * interpPeakAmount, 2f + 10f * interpPeakAmount), SpriteEffects.None, 0f);
            sb.EndBlendState(false, DrawMode.World, false);
        }
        public override void SetDefaults()
        {
            Projectile.friendly = true;
            Projectile.penetrate = -1;
            Projectile.tileCollide = false;
            Projectile.usesLocalNPCImmunity = true;
            Projectile.localNPCHitCooldown = 120;
            Projectile.DamageType = DamageClass.Melee;
            Projectile.timeLeft = 900;
            Projectile.extraUpdates = 1;
            Projectile.hide = true;
        }
        public override bool ShouldUpdatePosition()
        {
            return false;
        }
        public override bool PreDraw(ref Color lightColor)
        {
            return false;
        }
        public override void ModifyDamageHitbox(ref Rectangle hitbox)
        {
            Point size = new Point((int)(HitDimensions.X * drawScale), (int)(HitDimensions.Y * drawScale));
            ref int ptr = ref hitbox.Width;
            int num = size.X;
            int num2 = size.Y;
            ptr = num;
            hitbox.Height = num2;
            Point point = (Projectile.Center + faceVector * HitDistance * drawScale - size.ToVector2() / 2f).ToPoint();
            ptr = ref hitbox.X;
            ref int ptr2 = ref hitbox.Y;
            num2 = point.X;
            num = point.Y;
            ptr = num2;
            ptr2 = num;
            this.hitbox = hitbox;
        }
        public virtual float Interpolate(float progress)
        {
            return progress;
        }
        public override bool? CanDamage()
        {
            return interpPeakAmount > HitWindow;
        }
        public Vector2 HitDimensions { get; internal set; } = new Vector2(64f);
        public virtual float ModifyScale()
        {
            return 1f;
        }
        public virtual Vector2 CalculateFaceVector(Player player, float attackRangeMod = 1f, bool invertSign = false)
        {
            int sign = (AlternateSwings && combo % 2 == 0 ? -1 : 1) * -initialDirection * (invertSign ? -1 : 1);
            float range = AttackRange * attackRangeMod;
            return (Vector2.Normalize(Projectile.velocity) * 2f).RotatedBy((double)(range / 2f * sign + range * (float)-(float)sign * interpSwingProgress), default);
        }
        private static Vector2 GetHandOffset(Player player)
        {
            int frame = player.bodyFrame.Y / player.bodyFrame.Height;
            Vector2 offset = default;
            switch (frame)
            {
                case 1:
                    offset = new Vector2(-9f, -10f);
                    break;
                case 2:
                    offset = new Vector2(5f, -7f);
                    break;
                case 3:
                    offset = new Vector2(9f, 7f);
                    break;
                case 4:
                    offset = new Vector2(6f, 11f);
                    break;
            }
            return offset * new Vector2(player.direction, 1f);
        }
        private void SetHandFrame(Player player)
        {
            float num = MathHelper.WrapAngle(faceVector.ToRotation() + 1.5707964f);
            float angle = Math.Abs(num);
            int dir = Math.Sign(num);
            if (dir != player.direction && interpSwingProgress > 0.5f && interpSwingProgress < 0.75f)
            {
                player.direction = dir;
            }
            int frame;
            if (angle <= 0.6f)
            {
                frame = 1;
            }
            else if (angle >= 1.4707963f && angle <= 2.3707964f)
            {
                frame = 3;
            }
            else if (angle > 2.3561945f)
            {
                frame = 4;
            }
            else
            {
                frame = 2;
            }
            player.bodyFrame.Y = player.bodyFrame.Height * frame;
        }
        protected Vector2 HandleOriginWithFlip(float x, float defaultY, float flippedY)
        {
            return new Vector2(x, isAlternateSwing ? initialDirection == -1 ? defaultY : flippedY : initialDirection == -1 ? flippedY : defaultY);
        }
        protected Vector2 HandleOriginWithFlip(Texture2D tex, Vector2 origin)
        {
            return HandleOriginWithFlip(origin.X, origin.Y, tex.Height - origin.Y);
        }
        public override void AI()
        {
            Player player = Main.player[Projectile.owner];
            player.heldProj = Projectile.whoAmI;
            player.itemTime = 5;
            Projectile.width = hitbox.Width * 2;
            Projectile.height = hitbox.Height * 2;
            if (initialDirection == 0)
            {
                initialDirection = player.direction;
                itemAnimationMax = player.itemAnimationMax;
            }
            staticPos = player.MountedCenter + new Vector2(0f, player.gfxOffY);
            combo = player.GetModPlayer<HeavyWeaponPlayer>().claymoreCombo;
            swingProgress = 1f - MathHelper.Clamp(player.itemAnimation / (float)itemAnimationMax, 0f, 1f);
            peakAmount = MathHelper.Clamp(1f - Math.Abs(swingProgress - 0.5f) / 0.5f, 0f, 1f);
            interpSwingProgress = Interpolate(swingProgress);
            interpPeakAmount = MathHelper.Clamp(1f - Math.Abs(interpSwingProgress - 0.5f) / 0.5f, 0f, 1f);
            isAlternateSwing = AlternateSwings && combo % 2 == 0;
            spriteFx = isAlternateSwing ? initialDirection == -1 ? SpriteEffects.None : SpriteEffects.FlipVertically : initialDirection == -1 ? SpriteEffects.FlipVertically : SpriteEffects.None;
            faceVector = CalculateFaceVector(player, 1f, false);
            SetHandFrame(player);
            float angle = faceVector.ToRotation();
            Projectile.Center = staticPos + GetHandOffset(player);
            Projectile.rotation = angle - 1.5707964f;
            drawAngle = CalculateFaceVector(player, drawAngleRangeMod, false).ToRotation() + 0.7853982f;
            drawScale = Projectile.scale * ModifyScale();
            bladeHandle = Projectile.Center + Projectile.velocity;
            bladeTip = Projectile.Center + (drawAngle - 0.7853982f).ToRotationVector2() * HitDimensions.Y * drawScale * bladeTipOffsetMod;
            drawAngleWithoutFlip = drawAngle;
            if (useSmartAngle)
            {
                drawAngle -= isAlternateSwing ? initialDirection == -1 ? 0f : 1.5707964f : initialDirection == -1 ? 1.5707964f : 0f;
            }
            if (player.itemAnimation == 1 || player.frozen || player.dead)
            {
                Projectile.Kill();
            }
        }


    }
}
